/**
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { ComputedRef, Ref } from 'vue';
import { DataGridColumn, SortType } from '../data-grid.props';
import { ColumnRenderContext } from './use-column';
import { DataViewFilter, DataViewSorter } from './use-data-view';
import { Condition } from '../../../condition/src/types';
import { EditorType } from '../../../dynamic-form';

export type FilterRelation = 0 | 1;
export type FilterFunction = (dataItem: any) => boolean;

export interface DataFilter {
    relation: FilterRelation;
    filterFunctions: FilterFunction[];
    children: DataFilter[];
}

export enum HeaderCellStatus {
    none = 0,
    filterable = 1,
    sortable = 2,
    filtered = 4,
    sorted = 8,
    ascending = 16,
    descending = 32
}

export interface DataGridHeaderCell {
    actualWidth: number;
    children: DataGridHeaderCell[];
    depth: number;
    layer: number;
    left: number;
    field: string;
    parent: DataGridHeaderCell | null;
    resizable: boolean;
    title: string;
    status: HeaderCellStatus;
    popoverRef: Ref<any>;
    showPopover: boolean;
    column: DataGridColumn | null;
    filter?: any;
    filterValue: any;
    filterHistory?: any[];
    sortType: SortType;
    showSetting?: boolean;
}

export enum CellMode {
    readonly,
    editable,
    editing
}

export enum VisualDataType {
    data,
    group,
    summary
}

export enum VisualDataStatus {
    initial,
    editing
}

export interface VisualDataCell {
    actualHeight?: number;
    cellHeight?: number;
    colSpan: number;
    data: any;
    editingData: any;
    getEditor: (cell: VisualDataCell) => any;
    field: string;
    formatter?: (cell: VisualDataCell, visualDataRow: any) => any;
    index: number;
    mode: CellMode;
    ref?: any;
    rowSpan: number;
    setRef: (vnode: any) => void;
    spannedBy?: VisualDataCell;
    spanned?: VisualDataCell[];
    parent: any;
    update: (value: any) => void;
    accept: () => void;
    cancel: () => void;
}

export interface VisualData {
    collapse?: boolean;
    data: Record<string, VisualDataCell>;
    details?: VisualData[];
    groupField?: string;
    groupValue?: any;
    layer: number;
    index: number;
    dataIndex: number;
    top: number;
    type: VisualDataType;
    ref?: any;
    height?: number;
    pre?: any;
    refreshKey?: string;
    setRef: (vnode: any) => void;
    status: VisualDataStatus;
}

export interface UseVisualData {
    getVisualData: (start: number, end: number, pre?: VisualData, forceToRefresh?: boolean) => VisualData[];

    maxVisibleRowIndex: Ref<number>;

    minVisibleRowIndex: Ref<number>;

    toggleGroupRow: (status: 'collapse' | 'expand', groupRow: VisualData, visibleDatas: VisualData[]) => VisualData[];
}

export interface UseCellPosition {
    calculateCellPositionInRow: (columns: DataGridColumn[]) => Record<string, { left: number; width: number }>;

    cellKey: (dataItem: VisualData, columnIndex: number) => string;

    cellPosition: (cell: VisualDataCell, cellPositionMap: Record<string, { left: number; width: number }>) => Record<string, any>;

    rowKey: (dataItem: VisualData) => string;

    rowPosition: (dataItem: VisualData) => Record<string, any>;

    rowSpanCellPosition: (
        visualDataItem: VisualData,
        cell: VisualDataCell,
        cellPositionMap: Record<string, { left: number; width: number }>
    ) => Record<string, any>;

    groupCellPosition: (
        groupCell: VisualDataCell,
        cellPositionMap: Record<string, { left: number; width: number }>,
        layer: number
    ) => Record<string, any>;

    summaryCellPosition: (
        groupCell: VisualDataCell,
        cellPositionMap: Record<string, { left: number; width: number }>,
        layer: number
    ) => Record<string, any>;
}

export interface UseVirtualScroll {
    onMouseDownScrollThumb: ($event: MouseEvent, gridContentRef: Ref<any>, thumbType: 'vertical' | 'horizontal') => void;

    onWheel: (payload: WheelEvent) => void;

    dataGridWidth: Ref<number>;

    gridDataStyle: ComputedRef<Record<string, any>>;

    gridHeaderColumnsStyle: ComputedRef<Record<string, any>>;

    gridMergedDataStyle: ComputedRef<Record<string, any>>;

    gridSideStyle: ComputedRef<Record<string, any>>;

    fitHorizontalScroll: () => void;

    viewPortHeight: Ref<number>;

    viewPortWidth: Ref<number>;

    horizontalScrollThumbStyle: ComputedRef<Record<string, any>>;

    leftFixedGridDataStyle: ComputedRef<Record<string, any>>;

    leftFixedGridHeaderColumnsStyle: ComputedRef<Record<string, any>>;

    leftFixedGridMergedDataStyle: ComputedRef<Record<string, any>>;

    reCalculateVisualDataRows: (forceToRefresh?: boolean) => void;

    resetScroll: () => void;

    rightFixedGridDataStyle: ComputedRef<Record<string, any>>;

    rightFixedGridHeaderColumnsStyle: ComputedRef<Record<string, any>>;

    rightFixedGridMergedDataStyle: ComputedRef<Record<string, any>>;

    shouldShowHorizontalScrollbar: ComputedRef<boolean>;

    shouldShowVirticalScrollbar: ComputedRef<boolean>;

    verticalScrollThumbStyle: ComputedRef<Record<string, any>>;

    offsetX: Ref<number>;

    offsetY: Ref<number>;
}

export interface UseRow {
    gridRowClass(dataItem: VisualData): Record<string, any>;

    sidebarRowClass(dataItem: VisualData): Record<string, any>;

    onClickRow: ($event: MouseEvent, dataItem: VisualData) => any;

    onMouseoverRow: ($event: MouseEvent, dataItem: VisualData) => any;
}

export interface UseFitColumn {
    calculateColumnHeaders: (context: Ref<ColumnRenderContext>) => void;

    calculateColumnsSize: (context: Ref<ColumnRenderContext>, gridContentElement: any, viewPortWidth: Ref<number>) => void;

    calculateColumnsWidth: (context: Ref<ColumnRenderContext>) => void;
}

export interface UseSidebar {
    showRowCheckbox: Ref<boolean>;

    showRowNumer: Ref<boolean>;

    sidebarWidth: ComputedRef<number>;

    sidebarCellPosition: (dataItem: VisualData) => Record<string, any>;

    sidebarCornerCellStyle: ComputedRef<Record<string, any>>;
}

export interface UseGroupData {
    collpaseGroupIconClass: (groupRow: VisualData) => Record<string, boolean>;

    generateGroupData: (groupFields: string[], rawData: any[], columnContext: ColumnRenderContext) => any[];

    groupFields: Ref<string[]>;

    shouldGroupingData: Ref<boolean>;
}

export interface UseColumnFilter {

    getFilterEditor: (headerCell: DataGridHeaderCell) => any;

}

export interface UseFilter {
    addColumnFilter: (headerCell: DataGridHeaderCell) => void;

    apply: (dataItem: any) => boolean;

    clearCondition: () => void;

    conditions: Ref<Condition[]>;

    getFilterEditorType: (column: DataGridColumn) => EditorType;

    removeColumnFilter: (headerCell: DataGridHeaderCell) => void;

    removeCondition: (id: string) => void;
}

export interface UseDataView {
    insertNewDataItem: () => void;

    removeDataItem: (dataIndex: number) => void;

    changePageSizeTo: (newPageSize: number) => void;

    collapse: (collapseField: string, collapseValue: any) => any[];

    dataView: Ref<any[]>;

    expand: (expandField: string, expandValue: any) => any[];

    getRange: (filters: DataViewFilter[], start: number, end: number) => any[];

    navigatePageTo: (pageIndex: number) => void;

    summaries: Map<string, number>;

    totalItems: ComputedRef<number>;

    addFilter: (filterKey: string, filter: DataViewFilter) => any[];

    removeFilter: (filterKey: string) => any[];

    rawView: Ref<any[]>;

    addSorter: (sortKey: string, sorter: DataViewSorter) => any[];

    removeSorter: (sortKey: string) => any[];

    setSorters: (sorters: DataViewSorter[]) => void;

    filters: Ref<DataViewFilter[]>;

    removeAllFilter: () => any[];

    updateDataView: () => void;

    sorters: Ref<DataViewSorter[]>;

    refresh: () => void;
}

export interface UseSort {

    getSorterByColumn: (column: DataGridColumn) => any;

    updateSorter: (headerCell: DataGridHeaderCell, dataView: UseDataView) => void;
}

export interface UseColumn {
    applyColumnSorter: (dataView: UseDataView, sorterComposition: UseSort) => void;

    applySortableColumns: (sortableColumns: DataGridColumn[], dataView: UseDataView, sorterComposition: UseSort) => void;

    collectionFilterableColumns: () => DataGridColumn[];

    collectionSortableColumns: () => DataGridColumn[];

    columnContext: Ref<ColumnRenderContext>;

    hasLeftFixedColumn: ComputedRef<boolean>;

    hasRightFixedColumn: ComputedRef<boolean>;

    updateColumnSettingIcon: () => void;
}

export interface UseResize {
    onClickColumnResizeBar: ($event: MouseEvent, columnField: string) => any;

    resizeHandleStyle: Ref<Record<string, any>>;

    resizeOverlayStyle: Ref<Record<string, any>>;
}

export interface UseEdit {
    getEditor: (cell: VisualDataCell, column: DataGridColumn, visualDataRow: VisualData) => any;

    onClickCell: ($event: MouseEvent, cell: VisualDataCell) => any;

    onEditingRow: (visualDataRow: VisualData) => any;

    acceptEditingRow: (visualDataRow: VisualData) => any;

    cancelEditingRow: (visualDataRow: VisualData) => any;

    getEditingSnapshot: (dataIdentify: string) => VisualData | null;
}

export interface UseGroupColumn {
    getGridHeaderCells: (columns: DataGridColumn[]) => Map<string, DataGridHeaderCell>;
}

export interface UseSelection {
    getSelectionRow: () => VisualData;

    setSelectionRow: (visibleDatas: Ref<VisualData[]>, selectedDataId: string) => void;
}

export interface UseCommandColumn {
    applyCommands: (columns: Ref<DataGridColumn[]>) => void;
}

export interface UseFilterHistory {
    getFilterHistory: (headerCell: DataGridHeaderCell) => any[];

    setFilterHistory: (headerCell: DataGridHeaderCell, filterHistory: any[]) => void;

    removeFilterHistory: (headerCell: DataGridHeaderCell, filterString: string) => void;

    updateFilterHistory: (headerCell: DataGridHeaderCell, filterString: string) => void;
}

export interface UseVisualDataBound {

    updateRowPosition: (visualData: VisualData, dataItem: any) => void;

    updateVisualInfomation: (vnode: any, targetCell: VisualDataCell, dataItem: any) => void;
}

export interface UseVisualDataCell {

    // eslint-disable-next-line max-len
    createCellByColumn: (column: DataGridColumn, index: number, dataItem: any, parent: VisualData, preVisualData: VisualData) => VisualDataCell;

    createCellByField: (targetField: string, index: number, dataItem: any, parent: VisualData, colSpan?: number) => VisualDataCell;
}

// eslint-disable-next-line max-len
export type VisualDataRender = (dataItem: any, preDataItem: any, preRow: VisualData, rowIndex: number, top: number, columns: DataGridColumn[]) => VisualData;

export interface UseDataRow {

    createEmptyRow: (type: VisualDataType, index: number, dataItem: any, pre: any, top: number) => VisualData;

    // eslint-disable-next-line max-len
    createNewRowFromDataItem: (columns: DataGridColumn[], dataItem: any, preDataItem: any, preRow: VisualData, rowIndex: number, top: number) => VisualData;

    // eslint-disable-next-line max-len
    renderDataRow: VisualDataRender;
}

export interface UseGroupRow {
    renderGroupRow: VisualDataRender;
}

export interface UseSummaryRow {
    renderSummaryRow: VisualDataRender;
}

export interface UseDragColumn {
    dragstart: (e: DragEvent, item: any, index: number) => void;

    dragenter: (e: DragEvent, index: number) => void;

    dragover: (e: DragEvent, index: number) => void;

    dragend: (e: DragEvent, item: any) => void;

    dropOnGroupPanel: (e: DragEvent) => void;

    isDragging: Ref<boolean>;

    groupColumnItems: ComputedRef<{ name: string; value: string }[]>;
}
